package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.bean.DirSettingBO;
import com.uinnova.product.eam.comm.bean.DirSettingDTO;
import com.uinnova.product.eam.comm.model.es.ClassSetting;
import com.uinnova.product.eam.comm.model.es.DirSetting;
import com.uinnova.product.eam.comm.model.es.EamArtifactElement;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.model.ClassSettingDTO;
import com.uinnova.product.eam.model.dmv.ClassDefinitionVO;
import com.uinnova.product.eam.model.enums.CategoryTypeEnum;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.IOperateSettingService;
import com.uinnova.product.eam.service.es.EamArtifactElementDao;
import com.uinnova.product.eam.service.es.EamClassSettingDao;
import com.uinnova.product.eam.service.es.EamDirSettingDao;
import com.uinnova.product.vmdb.comm.model.ci.CcCiClass;
import com.uino.bean.cmdb.base.ESCIAttrDefInfo;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.dao.util.ESUtil;
import com.uino.service.cmdb.microservice.ICIClassSvc;
import com.uino.service.cmdb.microservice.impl.CIClassSvc;
import com.uino.util.sys.BeanUtil;
import com.uino.util.sys.SysUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bingshen
 */
@Service
public class OperateSettingSvcImpl implements IOperateSettingService {

    @Autowired
    private EamClassSettingDao eamClassSettingDao;

    @Autowired
    private EamDirSettingDao eamDirSettingDao;

    @Autowired
    private CIClassSvc classSvc;

    @Resource
    private EamArtifactElementDao eamArtifactElementDao;

    @Resource
    private ICIClassSvc iciClassSvc;

    @Resource
    private EamCategorySvc categorySvc;

    @Override
    public Long saveClassSetting(ClassSetting classSetting) {
        classSetting.setId(ESUtil.getUUID());
        classSetting.setCreateUser(SysUtil.getCurrentUserInfo().getLoginCode());
        classSetting.setModifyUser(SysUtil.getCurrentUserInfo().getLoginCode());
        classSetting.setCreateTime(BinaryUtils.getNumberDateTime());
        classSetting.setCreateTime(BinaryUtils.getNumberDateTime());
        classSetting.setModifyTime(BinaryUtils.getNumberDateTime());
        return eamClassSettingDao.saveOrUpdate(classSetting);
    }

    @Override
    public Integer deleteClassSettingById(Long id) {
        ClassSetting classSetting = eamClassSettingDao.getById(id);
        if (classSetting == null) {
            return -1;
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("classId",classSetting.getClassId()));
        eamDirSettingDao.deleteByQuery(query, false);
        return eamClassSettingDao.deleteById(id);
    }

    @Override
    public Boolean addDirSetting(DirSettingBO dirSettingBO) {
        if (dirSettingBO.getDirSettingDTO() == null || dirSettingBO.getDirSettingDTO().size() <= 0) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.termQuery("classId",dirSettingBO.getClassId()));
            eamDirSettingDao.deleteByQuery(boolQueryBuilder, true);
            return true;
        }
        List<DirSettingDTO> dirSettingDTO = dirSettingBO.getDirSettingDTO();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("classId",dirSettingDTO.get(0).getClassId()));
        eamDirSettingDao.deleteByQuery(boolQueryBuilder, true);
        for (DirSettingDTO settingDTO : dirSettingDTO) {
            DirSetting dirSetting = new DirSetting();
            BeanUtils.copyProperties(settingDTO, dirSetting);
            dirSetting.setId(ESUtil.getUUID());
            dirSetting.setParentId(0L);
            dirSetting.setCreateUser(SysUtil.getCurrentUserInfo().getLoginCode());
            dirSetting.setModifyUser(SysUtil.getCurrentUserInfo().getLoginCode());
            dirSetting.setCreateTime(BinaryUtils.getNumberDateTime());
            dirSetting.setModifyTime(BinaryUtils.getNumberDateTime());
            Long parentId = eamDirSettingDao.saveOrUpdate(dirSetting);
            //下面递归复制他下面孩子
            copyChildDirSetting(settingDTO,parentId);
        }

        return true;
    }

    @Override
    public List<ClassSetting> getClassSettingList(Long artifactId) {
        List<ClassSetting> listCount = eamClassSettingDao.getListByCdt(new ClassSetting());
        if (listCount == null || listCount.size() <= 0) {
            return new ArrayList<>();
        }
        Page<ClassSetting> order = eamClassSettingDao.getSortListByQuery(1, 10000, QueryBuilders.boolQuery(), "order"
                , true);
        List<ClassSetting> data = order.getData();
        if (data == null || data.size() <= 0) {
            return new ArrayList<>();
        }
        List<Long> classIdList = data.stream().map(ClassSetting::getClassId).filter(Objects::nonNull).collect(Collectors.toList());
        List<ESCIClassInfo> classInfos = classSvc.queryESClassInfoByIds(classIdList);
        Map<Long, String> classMap = classInfos.stream().collect(Collectors.toMap(CcCiClass::getId, CcCiClass::getClassName));
        List<ClassSetting> deleteClassSettings = new ArrayList<>();
        for (ClassSetting classSetting : data) {
            String className = classMap.get(classSetting.getClassId());
            if (StringUtils.isNotBlank(className)) {
                classSetting.setClassName(className);
            }else{
                deleteClassSettings.add(classSetting);
            }
        }
        data.removeAll(deleteClassSettings);
        return artifactId == null ? data : filterByArtifact(artifactId, data);
    }

    private List<ClassSetting> filterByArtifact(Long artifactId, List<ClassSetting> classSettings) {
        List<EamArtifactElement> eamArtifactElements = getEamArtifactElements(artifactId);

        List<ClassSetting> list = new ArrayList<>();

        for (ClassSetting classSetting : classSettings) {
            String settingClassId = Objects.toString(classSetting.getClassId());
            filterArtifactElement(eamArtifactElements, list, classSetting, settingClassId);
        }

        return list;
    }

    private void filterArtifactElement(List<EamArtifactElement> eamArtifactElements, List<ClassSetting> list,
                                       ClassSetting classSetting, String settingClassId) {
        // 架构资产类型
        Integer architectureAssetType = 2;
        for (EamArtifactElement eamArtifactElement : eamArtifactElements) {
            if (!architectureAssetType.equals(eamArtifactElement.getType())) {
                continue;
            }
            for (String element : eamArtifactElement.getElements()) {
                JSONObject elementJson = JSON.parseObject(element);
                String artifactContainsClassId = Objects.toString(elementJson.get("id"));
                Boolean viewFlag = (Boolean) elementJson.get("viewFlag");
                if (viewFlag && settingClassId.equals(artifactContainsClassId)) {
                    list.add(classSetting);
                    break;
                }
            }
        }
    }

    private List<EamArtifactElement> getEamArtifactElements(Long artifactId) {
        BoolQueryBuilder queryElement = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("artifactId", artifactId));
        return eamArtifactElementDao.getListByQuery(queryElement);
    }

    @Override
    public List<DirSettingDTO> getDirSettingByClassId(Long classId) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("classId", classId));
        List<DirSetting> dirSettingList = eamDirSettingDao.getListByQuery(boolQueryBuilder);
        if (dirSettingList == null || dirSettingList.size() <= 0) {
            return new ArrayList<>();
        }
        List<DirSetting> parentDirSettingList =
                dirSettingList.stream().filter(item -> item.getParentId() == 0L).sorted(Comparator.comparing(DirSetting::getOrder)).collect(Collectors.toList());
        //递归查询目录配置信息
        List<DirSettingDTO> convertDirSetting = convert(dirSettingList);
        List<DirSettingDTO> convertParentDirSetting = convert(parentDirSettingList);
        findDirSetting(convertDirSetting, convertParentDirSetting);
        return convertParentDirSetting;
    }

    @Override
    public Integer saveClassSettingList(List<ClassSetting> classSettings) {
        for (int i = 0; i < classSettings.size(); i++) {
            classSettings.get(i).setOrder(i+1);
        }
        return eamClassSettingDao.saveOrUpdateBatch(classSettings);
    }

    @Override
    public Integer judgeDirLevel(Long parentId) {
        List<DirSetting> count = new ArrayList<>();
        if (parentId == 0) {
            return 0;
        }
        DirSetting dirSetting = eamDirSettingDao.getById(parentId);

        count.add(dirSetting);
        //递归调用上层目录一直到parentId等于0
        queryDirLevel(dirSetting.getParentId(),count);

        return count.size();
    }

    @Override
    public List<ClassSettingDTO> isMkClassDir() {
        //查找所有操作设置的分类
        List<ClassSetting> classSettingList = getClassSettingList(null);
        if(CollectionUtils.isEmpty(classSettingList)){
            return Collections.emptyList();
        }
        //查找基于分类创建的分类文件夹在架构资产里面
        List<EamCategory> dirList = categorySvc.queryByType(CategoryTypeEnum.SYSTEM.val(), null, null, LibType.DESIGN);
        if (CollectionUtils.isEmpty(dirList)) {
            //没有基于分类配置创建分类文件夹
            return classSettingList.stream().map(item -> EamUtil.copy(item, ClassSettingDTO.class)).collect(Collectors.toList());
        }
        //基于分类配置创建了系统文件夹
        List<String> classIdList = dirList.stream().map(EamCategory::getCiCode).collect(Collectors.toList());
        List<ClassSetting> mkedClassDir = classSettingList.stream().filter(item -> classIdList.contains(String.valueOf(item.getClassId()))).collect(Collectors.toList());
        List<Long> collect = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(mkedClassDir)) {
            collect = mkedClassDir.stream().map(ClassSetting::getClassId).collect(Collectors.toList());
        }
        List<ClassSettingDTO> result = new ArrayList<>();
        for (ClassSetting classSetting : classSettingList) {
            ClassSettingDTO dto = EamUtil.copy(classSetting, ClassSettingDTO.class);
            if (collect.contains(classSetting.getClassId())) {
                dto.setIsMkDir(false);
            }
            result.add(dto);
        }
        return result;
    }

    @Override
    public List<ClassDefinitionVO> findClassDefinitionList() {
        List<ClassSetting> classList = getClassSettingList(null);
        List<ClassDefinitionVO> classDefinitionList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(classList)) {
            classList.forEach(classSet -> {
                // 查询属性定义
                if (classSet != null && classSet.getClassId() != null) {
                    ESCIClassInfo esciClassInfo = iciClassSvc.queryESClassInfoById(classSet.getClassId());
                    if (esciClassInfo != null && !CollectionUtils.isEmpty(esciClassInfo.getAttrDefs())) {
                        List<ESCIAttrDefInfo> attrDefs = esciClassInfo.getAttrDefs();
                        ClassDefinitionVO classDefinitionVO = new ClassDefinitionVO();
                        classDefinitionVO.setClassSet(classSet);
                        classDefinitionVO.setAttrDefList(attrDefs);
                        classDefinitionList.add(classDefinitionVO);
                    }
                }
            });
        }
        return classDefinitionList;

    }

    @Override
    public Boolean addPlanBindClass(Long classId) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("classId",classId));
        List<ClassSetting> classSettingList = eamClassSettingDao.getListByQuery(boolQueryBuilder);
        if (null != classSettingList && classSettingList.size() > 0) {
            return true;
        }else{
            long count = eamClassSettingDao.countByCondition(QueryBuilders.boolQuery());
            ClassSetting classSetting = new ClassSetting();
            classSetting.setId(ESUtil.getUUID());
            classSetting.setCreateUser(SysUtil.getCurrentUserInfo().getLoginCode());
            classSetting.setModifyUser(SysUtil.getCurrentUserInfo().getLoginCode());
            classSetting.setCreateTime(BinaryUtils.getNumberDateTime());
            classSetting.setModifyTime(BinaryUtils.getNumberDateTime());
            classSetting.setClassId(classId);
            classSetting.setOrder((int) ++count);
            eamClassSettingDao.saveOrUpdate(classSetting);
            return true;
        }
    }

    private void queryDirLevel(Long parentId, List<DirSetting> count) {
        if (parentId == 0) {
            return;
        }
        DirSetting dirSetting = eamDirSettingDao.getById(parentId);
        count.add(dirSetting);
        queryDirLevel(dirSetting.getParentId(),count);
    }

    @Override
    public List<ClassSetting> getEsSettings() {
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();

        return eamClassSettingDao.getListByQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("domainId", domainId)));
    }

    private List<DirSettingDTO> convert(List<DirSetting> dirSettings) {
        return dirSettings.stream().map(item -> {
            DirSettingDTO dirSettingDTO = new DirSettingDTO();
            BeanUtil.copyProperties(item, dirSettingDTO);
            return dirSettingDTO;
        }).collect(Collectors.toList());
    }

    private void findDirSetting(List<DirSettingDTO> convertDirSetting, List<DirSettingDTO> convertParentDirSetting) {
        if (convertParentDirSetting == null || convertParentDirSetting.size() <= 0) {
            return;
        }
        for (DirSettingDTO dirSettingDTO : convertParentDirSetting) {
            List<DirSettingDTO> childDirSettingDTO = convertDirSetting.stream().filter(item -> item.getParentId().equals(dirSettingDTO.getId())).sorted(Comparator.comparing(DirSettingDTO :: getOrder)).collect(Collectors.toList());
            dirSettingDTO.setChildNode(childDirSettingDTO);
            findDirSetting(convertDirSetting,childDirSettingDTO);
        }
    }

    /**
     * 递归处理孩子配置
     * @param dirSettingDTO
     * @param parentId
     */
    private void copyChildDirSetting(DirSettingDTO dirSettingDTO, Long parentId) {
        if (dirSettingDTO.getChildNode() == null || dirSettingDTO.getChildNode().size() <= 0) {
            return;
        }
        for (DirSettingDTO settingDTO : dirSettingDTO.getChildNode()) {
            DirSetting dirSetting = new DirSetting();
            BeanUtils.copyProperties(settingDTO, dirSetting);
            dirSetting.setId(ESUtil.getUUID());
            dirSetting.setParentId(parentId);
            dirSetting.setCreateUser(SysUtil.getCurrentUserInfo().getLoginCode());
            dirSetting.setModifyUser(SysUtil.getCurrentUserInfo().getLoginCode());
            dirSetting.setCreateTime(BinaryUtils.getNumberDateTime());
            dirSetting.setModifyTime(BinaryUtils.getNumberDateTime());
            Long id = eamDirSettingDao.saveOrUpdate(dirSetting);
            copyChildDirSetting(settingDTO,id);
        }
    }


}
